package org.hagopa.games.moneypool.msgs;


import java.nio.ByteBuffer;

import java.security.NoSuchAlgorithmException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.hagopa.games.moneypool.msgs.ContentTypes.ChatMsg;
import org.hagopa.games.moneypool.msgs.ContentTypes.game.DiesThrow;
import org.hagopa.games.moneypool.msgs.ContentTypes.game.PropertyActionCT;
import org.hagopa.games.moneypool.msgs.ContentTypes.game.UpdateStatus;
import org.hagopa.games.moneypool.msgs.ContentTypes.game.UpgradePropCT;
import org.hagopa.games.moneypool.msgs.ContentTypes.game.VerificationCT;
import org.hagopa.games.moneypool.msgs.ContentTypes.service.ClientIntro;
import org.hagopa.games.moneypool.msgs.ContentTypes.service.EmptyContent;
import org.hagopa.games.moneypool.msgs.ContentTypes.service.PlayerType;
import org.hagopa.games.moneypool.msgs.ContentTypes.service.Version;
import org.hagopa.games.moneypool.utils.UsefulUtils;

public class Message {
	
	
	private long sessionId = 0;		// actually an unsigned int
        private String str_session = null;
	private int clientId = 0;
	private CommandsEnum Command;
	private int contentSz = 0;
	private IMsgContent contentHandler = null;
        private String clientIP=null;
        private String hashKey = null;
	//private ByteBuffer msgHeader = null;
	
	public String serializeStringContent(){
            String outstr = null;
            outstr = String.valueOf(Command.idx())+ contentHandler.getConcatContent() ;
            return outstr;
        }
        public void setClientIP(String cip)
        {
            this.clientIP = cip;
        }
        public void setHashKey(String hk)
        {
            this.hashKey = hk;
        }
	public long getSessionId() {
		return sessionId;
	}
        public void setStrSession(String session)
        {
            this.str_session = session;
        }
	public void setSessionId(long sessionId) {
		this.sessionId = sessionId;
                
	}
	public int getClientId() {
		return clientId;
	}
	public void setClientId(int clientId) {
		this.clientId = clientId;
	}
	public CommandsEnum getCommand() {
		return this.Command;
	}
	public void setCommand(CommandsEnum command) {
		this.Command = command;
	}
	public int getContentSz() {
		return this.contentSz;
	}
	public void setContentSz(int contentSz) {
		this.contentSz = contentSz;
	}
	
	public IMsgContent getContentHandler() {
		return this.contentHandler;
	}
	public void setContentHandler(IMsgContent contentHandler) {
		this.contentHandler = contentHandler;
                this.contentSz = this.contentHandler.getSize();
	}
	
	public byte[] marshall()
	{
		byte [] out = new byte[256];
                try {
                            String hashStr = UsefulUtils.getMD5(clientIP, this.hashKey, this.serializeStringContent());

                            System.out.println("HASH MD5:" + hashStr);
                           this.str_session = hashStr;

                        } catch (NoSuchAlgorithmException ex) {
                            Logger.getLogger(Message.class.getName()).log(Level.SEVERE, null, ex);
                        }
		ByteBuffer msgHeader = ByteBuffer.allocate(256);
		//UsefulUtils.getSHA1(clientIp, key, serialized_content)
		msgHeader.putInt(this.clientId);


//@TPAZ - send unsigned-int over 'long' - Begin
//		msgHeader.putLong(this.sessionId);
//===============================Long session id is cancelled===============================
//		byte [] bbuf = new byte[4];
//
//		bbuf[0] = (byte) ((this.sessionId & 0xFF000000L) >> 24);
//		bbuf[1] = (byte) ((this.sessionId & 0x00FF0000L) >> 16);
//		bbuf[2] = (byte) ((this.sessionId & 0x0000FF00L) >> 8);
//		bbuf[3] = (byte) (this.sessionId & 0x000000FFL);
//
//		msgHeader.put(bbuf[0]);
//		msgHeader.put(bbuf[1]);
//		msgHeader.put(bbuf[2]);
//		msgHeader.put(bbuf[3]);
//@TPAZ - send unsinged-int over 'long' - End

                
		msgHeader.put(this.str_session.getBytes());
		msgHeader.putInt(this.Command.idx());
                System.out.println("[Message](marshall) - Marshalling Command:" + this.Command.getName() + "(" + this.Command.idx() + ")");
		
		if(null != this.contentHandler)
		{
			
			byte [] tmp = contentHandler.marshallToByte();
			if(null == tmp)
			{
				System.out.println("[Message](marshall) - TMP null");
				return null;
			}
                        this.contentSz = contentHandler.getSize();
                        msgHeader.putInt(this.contentSz);
			//@TP - debug:
			System.out.println("[Message](marshall) - tmp buffer size: " + tmp.length);
			msgHeader.put(tmp, 0, contentHandler.getSize());
			
			//return null;
		}
		msgHeader.rewind();
		//msgHeader.order(ByteOrder.BIG_ENDIAN);
		msgHeader.get(out, 0, out.length);
		return out;
	}
	
	public boolean unmarshall(byte [] data)
	{
            if(null == data)
            {
                    System.out.println("[Message](unmarshall) - Empty Data array");
                    return false;
            }

            ByteBuffer lmsgHeader = ByteBuffer.wrap(data);
            if(null == lmsgHeader)
                    return false;


            this.clientId = lmsgHeader.getInt();
            System.out.println("[Message] (unmarshall) from cid:" + this.clientId);
//@TPAZ - Recieve unsigned-int into 'long' - Begin
//		this.sessionId = lmsgHeader.getLong();
//===============================Long session id is cancelled===============================
//            int firstByte = 0;
//            int secondByte = 0;
//            int thirdByte = 0;
//            int fourthByte = 0;
//
//          //  int index = 4;
//
//            firstByte = (0x000000FF & ((int)lmsgHeader.get()));
//            secondByte = (0x000000FF & ((int)lmsgHeader.get()));
//            thirdByte = (0x000000FF & ((int)lmsgHeader.get()));
//            fourthByte = (0x000000FF & ((int)lmsgHeader.get()));
//
//            // cast into our Long type
//            this.sessionId = ((long) (firstByte << 24
//                            | secondByte << 16
//                        | thirdByte << 8
//                        | fourthByte))
//                       & 0xFFFFFFFFL;
//            System.out.println(   "sessionId:" +    this.sessionId);
    //@TPAZ - Recieve unsigned-int into 'long' - End
            String temp_session = null;
            byte [] tmp_bytes = new byte[64];
            lmsgHeader.get(tmp_bytes, 4, 36);
            temp_session = new String(tmp_bytes);
            int cmdTmp = lmsgHeader.getInt();

            if((10 < cmdTmp) && (cmdTmp < 1000))
            {

                    this.Command = CommandsEnum.getEnum(cmdTmp);
                    System.out.println("[Message](unmarshall) - Command name:" + this.Command.getName());
                    if(null == this.Command)
                    {
                            System.out.println("[Message](unmarshall) - Unknown Command!!!");
                            return false;
                    }
            }
            else
            {
                    System.out.println("[Message](unmarshall) - Unknown Command!!!");
                    return false;
            }

                this.contentSz = lmsgHeader.getInt();
                System.out.println("[Message](unmarshall) contentSize:" + this.contentSz);
                if(this.contentSz > 0)
                {
                        byte [] content = new byte[lmsgHeader.remaining()];
                        if(null == content || content.length < 2)
                        {
                                this.contentHandler = new EmptyContent();
                        }
                        else
                        {
                                switch(this.Command){
                                case SERV_HELLO:
                                        this.contentHandler = new Version();
                                        break;
                                case INTRO:
                                        this.contentHandler = new ClientIntro();
                                        break;

                                case READY:
                                        this.contentHandler = new PlayerType();
                                        break;
                                case UPDATE:
                                        this.contentHandler = new UpdateStatus();
                                        break;
//				case STATUS:
//					this.contentHandler = new StatusData();
//					lmsgHeader.get(content, 0, content.length);
//					this.contentHandler.unmarshallFromByte(content);
//					break;
                                case THR_DIES:
                                        this.contentHandler = new DiesThrow();
                                        break;
                                case MOVE_DONE:
                                        this.contentHandler = new EmptyContent();
                                        break;
                                case AC_BUY:
                                        this.contentHandler = new PropertyActionCT();
                                        System.out.println("\n [Message](unmarshall)Content is PropertyActionCT ");
                                        break;
                                case NG_AC_BUY:
                                        this.contentHandler = new VerificationCT();
                                        System.out.println("\n [Message](unmarshall)Content is VerificationCT ");
                                        break;
                                case AC_PAY:
                                        System.out.println("\n\nContent SIZE:" + this.contentSz + "\n--------------------\n");
                                        this.contentHandler = new PropertyActionCT();
                                        break;
                                case AC_SELL:
                                        System.out.println("\n [Message](unmarshall)Content is PropertyActionCT ");
                                        this.contentHandler = new PropertyActionCT();
                                        break;
                                case NG_AC_SELL:
                                        this.contentHandler = new VerificationCT();
                                        System.out.println("\n [Message](unmarshall)Content is VerificationCT ");
                                        break;
                                case NG_AC_EXCHANGE:
                                        this.contentHandler = new VerificationCT();
                                        System.out.println("\n [Message](unmarshall)Content is VerificationCT ");
                                        break;
                                case AC_UPGRADE:
                                        this.contentHandler = new UpgradePropCT();
                                        break;
                                case CHAT_MSG:
                                        this.contentHandler = new ChatMsg();
                                        System.out.println("\n\nContent SIZE:" + this.contentSz);
                                        System.out.println("\n Content: " + content);
                                        ((ChatMsg)this.contentHandler).setTotal_size(this.contentSz);
                                        break;
                                case RESIGN:
                                        System.out.println("\n\nRESIGN command - Content Empty:");
                                        break;
                                case DISCONNECT:
                                        System.out.println("\n\nRESIGN command - Content Empty:");
                                        break;

                                default:
                                                System.out.println("[Message](unmarshall) - Unknown data");
                                        return false;
                                }
                                lmsgHeader.get(content, 0, content.length);
                                this.contentHandler.unmarshallFromByte(content);
                        }
                    }
                try {
                        String hashStr = UsefulUtils.getMD5(clientIP, this.hashKey, this.serializeStringContent());

                        System.out.println("HASH MD5:" + hashStr);
                        if(hashStr.equals(temp_session))
                                return true;
                    } catch (NoSuchAlgorithmException ex) {
                        Logger.getLogger(Message.class.getName()).log(Level.SEVERE, null, ex);
                    }
		return false;
	}
	
}
